﻿using System;
using System.Collections.Generic;

using System.Text;
using System.Data;

namespace Efficient.DataAccess
{
    /// <summary>
    /// 扩展IDataReader接口的功能
    /// </summary>
    public static class ExtendDataReader
    {
        private enum FetchPosition
        {
            /// <summary>
            /// 位于记录集前面
            /// </summary>
            Previous,
            /// <summary>
            /// 处于记录集范围
            /// </summary>
            Match,
            /// <summary>
            /// 位于记录集后面
            /// </summary>
            After
        }
        /// <summary>
        /// 采用IDataReader转载单个实体类
        /// </summary>
        /// <typeparam name="T">实体类的泛型</typeparam>
        /// <param name="dr">DataReader对象</param>
        /// <param name="entity"></param>
        /// <param name="converter">转载方法</param>
        /// <returns>如果DataReader可读则返回第一个记录否则为null</returns>
        public static void FillEntity<T>(IDataReader dr, ref T entity, Reader2Entity<T> converter) where T : new()
        {
            if (dr.Read())
            {
                if (entity == null)
                {
                    entity = new T();
                }
                converter(entity, dr);
            }
        }
        /// <summary>
        /// 采用IDataReader装载实体类列表
        /// </summary>
        /// <typeparam name="T">实体类的泛型</typeparam>
        /// <param name="resultList">实体类的泛型列表</param>
        /// <param name="dr">DataReader对象</param>
        /// <param name="converter">转载方法</param>
        public static void FillList<T>(IDataReader dr, IList<T> resultList, Reader2Entity<T> converter) where T : new()
        {
            FillList<T>(dr, resultList, converter, 0, 0);
        }

        /// <summary>
        /// 加载实体类列表从指定的行号开始
        /// </summary>
        /// <typeparam name="T">实体类的泛型</typeparam>
        /// <param name="resultList">实体类的泛型列表</param>
        /// <param name="dr">DataReader对象</param>
        /// <param name="converter">转载方法</param>
        /// <param name="firstResult">开始行</param>
        public static void FillListFromIndex<T>(IDataReader dr, IList<T> resultList, Reader2Entity<T> converter, uint firstResult) where T : new()
        {
            FillList<T>(dr, resultList, converter, firstResult, 0);
        }

        /// <summary>
        /// 加载实体类列表直到指定的行号结束
        /// </summary>
        /// <typeparam name="T">实体类的泛型</typeparam>
        /// <param name="resultList">实体类的泛型列表</param>
        /// <param name="dr">DataReader对象</param>
        /// <param name="converter">转载方法</param>
        /// <param name="maxResults">最多返回的实体个数</param>
        public static void FillListToIndex<T>(IDataReader dr, IList<T> resultList, Reader2Entity<T> converter, uint maxResults) where T : new()
        {
            FillList<T>(dr, resultList, converter, 0, maxResults);
        }
        /// <summary>
        /// 从指定的行号区间加载实体类列表，开始、结束行均为0表示加载全部
        /// </summary>
        /// <typeparam name="T">实体类的泛型</typeparam>
        /// <param name="resultList">实体类的泛型列表</param>
        /// <param name="dr">DataReader对象</param>
        /// <param name="converter">转载方法</param>
        /// <param name="firstResult">开始行</param>
        /// <param name="maxResults">最多返回的实体个数</param>
        public static void FillList<T>(IDataReader dr, IList<T> resultList, Reader2Entity<T> converter, uint firstResult, uint maxResults) where T : new()
        {
            if (firstResult < 0)
            {
                throw new ArgumentException("起点记录下标必须大于等于0");
            }
            uint rowIndex = 0;
            uint maxIndex = firstResult + maxResults;
            while (dr.Read())
            {
                FetchPosition status = AssertReadNext(rowIndex, firstResult, maxIndex);
                rowIndex++;
                if (status == FetchPosition.Match)
                {
                    T entity = new T();
                    converter(entity, dr);
                    resultList.Add(entity);
                }
                else if (status == FetchPosition.After)
                {
                    break;
                }
            }
        }

        private static FetchPosition AssertReadNext(uint current, uint startIndex, uint endIndex)
        {
            if (startIndex >= 0 && endIndex == startIndex)
            {
                return current >= startIndex ? FetchPosition.Match : FetchPosition.Previous;
            }

            if (startIndex == 0 && endIndex > startIndex)
            {
                return current < endIndex ? FetchPosition.Match : FetchPosition.After;
            }
            if (current >= startIndex && current < endIndex)
            {
                return FetchPosition.Match;
            }
            else if (current < startIndex)
            {
                return FetchPosition.Previous;
            }
            return FetchPosition.After;
        }
    }
}
